package nl.unimaas.micc.umsnooker.simulation;

import java.util.HashMap;
import java.util.Set;

import nl.unimaas.micc.umsnooker.adt.def.List;
import nl.unimaas.micc.umsnooker.adt.impl.AVLTree;
import nl.unimaas.micc.umsnooker.domain.BilliardBall;
import nl.unimaas.micc.umsnooker.domain.Table;
import nl.unimaas.micc.umsnooker.domain.Tile;
import nl.unimaas.micc.umsnooker.simulation.event.EnterTileEvent;
import nl.unimaas.micc.umsnooker.simulation.event.Event;
import nl.unimaas.micc.umsnooker.simulation.event.LeaveTileEvent;
import nl.unimaas.micc.umsnooker.simulation.event.TilingEvent;

public class InTimeSimulation extends Simulation
{

	public InTimeSimulation(Set<BilliardBall> balls, Table table)
	{
		super(balls, table);
	}

	@Override
	public void init(Set<Event> initEvents)
	{
		initials = new HashMap<BilliardBall, BilliardBall>();
		events = new AVLTree<Float, Event>(timeComp);
		createFromStored(initials);

		for (Event e : initEvents)
		{
			for (BilliardBall b : e.getBalls(initials))
			{
				List<Event> l = ballEvents.get(b).get(null);
				l.insertLast(e);
				e.addListOccurrence(l.last());
				e.setPQOccurrence(events.insertItem(e.getTime(), e));
			}
		}

		super.init(initEvents);
	}

	@Override
	public Event fetchNextEvent()
	{
		return events.minElement();
	}

	@Override
	public void handleEvent(Event event)
	{
		if (event instanceof EnterTileEvent)
		{
			if (initials.get(((EnterTileEvent) event).getBall()).getTiles().contains(((EnterTileEvent) event).getTile()))
			{
				event.removeOccurrences();
				return;
			}
		}
		super.handleEvent(event);
		if (event instanceof EnterTileEvent)
		{
			queueEvents(((EnterTileEvent) event).getBall(), initials, ((EnterTileEvent) event).getTile());
			event.removeOccurrences();
		}
		else if (event instanceof LeaveTileEvent)
		{
			clearEvents(((LeaveTileEvent) event).getBall(), ((LeaveTileEvent) event).getTile());
		}
		else
		{
			for (BilliardBall ball : event.getBalls(initials))
			{

				clearEvents(ball);
				// go through all balls that are involved
				// and do the event scheduling
				queueEvents(ball, initials);
			}
		}

	}

	@Override
	public boolean hasNextEvent()
	{
		return events.size() > 1;
	}

}
